const slient = (e) => {
  e.stopPropagation();
  e.preventDefault();
};
class Composite {
  actionContainer = [];
  styleContainer = new Map();
  websocket = new (class WebsocketServer {
    socket = null;
    from = "user";
    to = "server";
    msgQueue = [];
    constructor() {
      // "ws://127.0.0.1:8080"
      try {
        this.socket = new WebSocket(
          `ws://${location.hostname || "127.0.0.1"}:8080`
        );
        this.socket.addEventListener("message", (e) => {
          const data = JSON.parse(e.data);
          console.log(data.msg);
        });
        this.socket.addEventListener("open", (e) => {
          this.send("ping");
          this.msgQueue.forEach((val) => this.send(val));
        });
      } catch (e) {
        console.log(e);
      }
    }
    send(msg) {
      try {
        this.socket.send(
          JSON.stringify({
            from: this.from,
            to: this.to,
            msg,
          })
        );
      } catch (e) {
        this.msgQueue.push(msg);
      }
    }
  })();
  constructor() {}
  addStyle(selector, css) {
    this.styleContainer.set(selector, css);
  }
  addAction(fun) {
    this.actionContainer.push(fun);
  }
  toString() {
    return JSON.stringify({
      style: this.mapToString(this.styleContainer),
      action: JSON.stringify(this.actionContainer),
    });
  }
  mapToString(map) {
    const entries = Array.from(map.entries());
    const obj = {};
    entries.forEach(([key, value]) => {
      obj[String(key)] = value;
    });
    return JSON.stringify(obj);
  }
  // uploadResources() {
  //   // websocket.send("clear|");
  //   // websocket.send("resources|" + JSON.stringify(window.lowCode.resources));
  // }
  sync() {
    // console.log(this.toString(), window.lowCode.resources);
    // websocket.send("hotReload|");
    this.websocket.send(
      "resources|" + JSON.stringify(window.lowCode.resources)
    );
    if (!window.lowCode.components) {
      alert("component not found!");
      return;
    }
    this.websocket.send("sync|" + JSON.stringify(window.lowCode.components));
    this.websocket.send("decode|" + this.toString());
  }
  upload(name, blob) {
    this.websocket.send("upload>" + name + "|" + blob);
  }
}

/**
 * get file name from path
 */
const getBaseName = (path) => {
  const slash = path.lastIndexOf("/");
  const reverse = path.lastIndexOf("\\");
  const mark = slash > reverse ? slash : reverse;
  if (mark === -1) return path;
  return path.substring(mark + 1);
};

if (!window.lowCode) window.lowCode = {};
window.lowCode.composite = new Composite();

window.addEventListener("keydown", (e) => {
  if (e.key === "Escape")
    layer.confirm(
      "完成修改？",
      {
        btn: ["确定", "关闭"], //按钮
      },
      function () {
        layer.closeAll();
        window.lowCode.composite.sync();
      },
      function () {}
    );
});

window.addEventListener("DOMContentLoaded", () => {
  // console.log("dev.js", window.lowCode.configArr, window.lowCode.configCssArr);

  const link = document.createElement("link");
  link.setAttribute("href", "dev/css/dev.css");
  link.setAttribute("rel", "stylesheet");
  document.head.append(link);

  const genForm = (name, value, inputType = "text") => {
    return `
  <div style="padding: 10px 20px;">
    <div class="layui-input-group">
      <div class="layui-input-prefix">${name}</div>
      <input type="${inputType}" name="${name}" placeholder="${name}" value="${value}" class="layui-input" devPropInput />
    </div>
  </div>
`;
  };

  class GenPropForm {
    name = "";
    value = "";
    type = "";
    content = "";
    seq = 0;
    constructor(name, value, type, seq) {
      this.name = name;
      this.value = value;
      this.type = type;
      this.seq = seq;
      this[this.type]();
    }
    collection() {
      for (let i = 0; i < this.name.length; i++) {
        this.content += new GenPropForm(
          this.name[i],
          this.value[i],
          "text"
        ).getContent();
      }
    }
    checkbox() {
      this.content = `
    <div class="layui-form" style="display: flex; justify-content: space-between; padding: 10px 20px;">
      <input type="checkbox" name="${this.name}" title="开启|关闭" lay-skin="switch" devPropInput ${this.value === "true" ? "checked" : ""}/>
    </div>
    `;
    }
    resources() {
      this.content = `
      <div class="layui-upload">
      <input devPropInput style="display: none" />
      <button type="button" class="layui-btn layui-btn-normal uploadBtn${this.seq}" >${this.name}</button> 
      <div class="layui-upload-list">
        <table class="layui-table">
          <colgroup>
            <col style="min-width: 100px;">
            <col width="150">
            <col width="260">
            <col width="150">
          </colgroup>
          <thead>
            <th>文件名</th>
            <th>大小</th>
            <th>上传进度</th>
            <th>操作</th>
          </thead>
          <tbody id="files-list${this.seq}"></tbody>
        </table>
      </div>
      <button type="button" class="layui-btn" id="action${this.seq}">开始上传</button>
    </div>
    `;
    }
    button() {}
    radio() {
      this.content = `
   <div style="padding: 10px 20px;">
    <div class="layui-input-group">
      <div class="layui-input-prefix">${this.name}</div>
      <input type="radio" name="${this.name}" placeholder="${this.name}" value="${this.value}" class="layui-input" devPropInput />
    </div>
  </div>
    `;
    }
    text() {
      this.content = genForm(this.name, this.value, this.type);
    }
    number() {
      this.content = genForm(this.name, this.value, this.type);
    }
    getContent() {
      return this.content;
    }
  }

  window.lowCode.resourcesSeq = [];
  //prop config
  window.lowCode.configArr.forEach((val) => {
    $(val.trigger(window.$, val.domSelector)).on("contextmenu", (event) => {
      // const content = val.desc
      //   .map((val) => genForm(val.name, val.value, val.inputType))
      //   .join("\n");
      const content = val.desc
        .map((val, seq) => {
          if (val.inputType === "resources") {
            window.lowCode.resourcesSeq.push(seq);
          }
          return new GenPropForm(
            val.name,
            val.value,
            val.inputType,
            seq
          ).getContent();
        })
        .join("\n");
      slient(event);
      layer.open({
        type: 1,
        shadeClose: true,
        content,
        btn: ["确定"],
        success: () => {
          layui.use(() => {
            if (val.desc.find((val) => val.inputType === "checkbox"))
              layui.form.render("checkbox");

            uploadEvent();
          });
        },
        btn1: () => {
          const inputs = Array.from(
            document.querySelectorAll("*[devPropInput]")
          );
          let offset = 0;
          val.desc.forEach((descItem, seq) => {
            const input = inputs[seq + offset];
            if (descItem.inputType === "resources") {
              if (input.value.length === 0) return;
              descItem.onchange(
                $,
                $(val.domSelector),
                input.value.split("|"),
                "res/img/"
              );
              window.lowCode.composite.addAction(
                `($, ele)=>(function ${descItem.onchange.toString()})(
                $,
                ele,
                ${JSON.stringify(input.value.split("|"))},
                "res/img/"
              )`
              );

              return;
            }

            if (descItem.inputType === "collection") {
              offset += descItem.name.length - 1;
              descItem.onchange(
                $,
                $(val.domSelector),
                inputs.slice(seq, seq + descItem.name.length)
              );

              window.lowCode.composite
                .addAction(`($, ele)=>(function ${descItem.onchange.toString()})(
                $,
                ele,
                ${JSON.stringify(inputs.slice(seq, seq + descItem.name.length).map((val) => ({ value: val.value })))},
                "res/img/"
              )`);
              return;
            }

            descItem.onchange($, $(val.domSelector), input);
            window.lowCode.composite.addAction(
              `($, ele)=>(function ${descItem.onchange.toString()})(
                $,
                ele,
                ${JSON.stringify({ value: input.value, checked: input.checked })}
              )`
            );
          });

          layer.closeAll();
        },
      });
    });
  });

  //css config
  window.lowCode.configCssArr?.forEach((val) => {
    $(val.trigger()).on("click", (event) => {
      slient(event);
      const content = val.desc
        .map((val) => genForm(val.name, val.value))
        .join("\n");
      layer.open({
        type: 1,
        shadeClose: true,
        content,
        btn: ["确定"],
        btn1: () => {
          const inputs = Array.from(
            document.querySelectorAll("input[devPropInput]")
          ).map((val) => val.value);
          let cssContent = $("#" + val.desc[0].cssTagSelector).text();
          val.desc.forEach((val, seq) => {
            if (val.value === inputs[seq]) return;
            val.value = inputs[seq];
            // cssContent =
            //   typeof val.onchange === "function"
            //     ? val.onchange(inputs[seq], seq, cssContent)
            //     : new Function(
            //         `const fun = (${val.onchange})('${inputs[seq]}','${seq}', \`${cssContent}\`); return fun`
            //       )();

            const action = `const fun = (${val.onchange})('${inputs[seq]}','${seq}', \`${cssContent}\`); return fun`;
            cssContent = new Function(action)();
          });

          const selector = "#" + val.desc[0].cssTagSelector;
          window.lowCode.composite.addStyle(selector, cssContent);
          $(selector).text(cssContent);

          layer.closeAll();
        },
      });
    });
  });
});

// window.addEventListener("DOMContentLoaded", () => {
//   // window.lowCode.composite.uploadResources();
// });

const uploadEvent = () => {
  // const num = $(".layui-upload").length;

  for (let i = 0; i < window.lowCode.resourcesSeq.length; i++) {
    const seq = window.lowCode.resourcesSeq[i];
    const cur = ".uploadBtn" + seq;
    var uploadListIns = layui.upload.render({
      elem: $(cur),
      elemList: $(`#files-list${seq}`), // 列表元素对象
      url:
        "http://" +
        (!location.hostname ? "127.0.0.1" : location.hostname) +
        ":8081/api/uploadProRes", // 实际使用时改成您自己的上传接口即可。
      accept: "file",
      multiple: true,
      auto: false,
      bindAction: `#action${seq}`,
      choose: function (obj) {
        var that = this;
        var files = (this.files = obj.pushFile()); // 将每次选择的文件追加到文件队列
        // 读取本地文件
        obj.preview(function (index, file, result) {
          var tr = $(
            [
              '<tr id="upload-' + index + '">',
              "<td>" + file.name + "</td>",
              "<td>" + (file.size / 1024).toFixed(1) + "kb</td>",
              '<td><div class="layui-progress" lay-filter="progress-demo-' +
                index +
                '"><div class="layui-progress-bar" lay-percent=""></div></div></td>',
              "<td>",
              '<button class="layui-btn layui-btn-xs demo-reload layui-hide">重传</button>',
              '<button class="layui-btn layui-btn-xs layui-btn-danger demo-delete">删除</button>',
              "</td>",
              "</tr>",
            ].join("")
          );

          // 单个重传
          tr.find(".demo-reload").on("click", function () {
            obj.upload(index, file);
          });

          // 删除
          tr.find(".demo-delete").on("click", function () {
            delete files[index]; // 删除对应的文件
            tr.remove(); // 删除表格行
            // 清空 input file 值，以免删除后出现同名文件不可选
            uploadListIns.config.elem.next()[0].value = "";
          });

          that.elemList.append(tr);
          // element.render("progress"); // 渲染新加的进度条组件
        });
      },
      done: function (res, index, upload) {
        // 成功的回调
        var that = this;
        const input = this.elem[0].parentElement.querySelector("input");
        input.value.length > 0 && (input.value += "|");
        input.value += res.data[0];
        // if(res.code == 0){ // 上传成功
        var tr = that.elemList.find("tr#upload-" + index);
        var tds = tr.children();
        tds.eq(3).html(""); // 清空操作
        delete this.files[index]; // 删除文件队列已经上传成功的文件
        return;
        //}
        this.error(index, upload);
      },
      allDone: function (obj) {
        console.log(obj);
      },
      error: function (index, upload) {
        var that = this;
        var tr = that.elemList.find("tr#upload-" + index);
        var tds = tr.children();
        tds.eq(3).find(".demo-reload").removeClass("layui-hide");
      },
    });
  }
};
